﻿using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Security.Cryptography;
using System.Text;

namespace Agile.Redsys
{
    /// <summary>
    /// Help class for generatig SHA1 signatures.
    /// </summary>
    public static class SignatureHelper
    {
        /// <summary>
        /// The _hash algorithm
        /// </summary>
        private static readonly HashAlgorithm _hashAlgorithm = new SHA1CryptoServiceProvider();

        /// <summary>
        /// Hashes the specified input.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns>System.String.</returns>
        private static string Hash(string input)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(input);
            bytes = _hashAlgorithm.ComputeHash(bytes);

            StringBuilder s = new StringBuilder();

            foreach (byte b in bytes)
                s.Append(b.ToString("x2")
                          .ToLower());

            return s.ToString();
        }

        /// <summary>
        /// Gets a SHA1 signature for extended recurring transaction requests.
        /// </summary>
        /// <param name="amount">The amount.</param>
        /// <param name="order">The order.</param>
        /// <param name="merchantCode">The merchant code.</param>
        /// <param name="currency">The currency.</param>
        /// <param name="sum">The sum.</param>
        /// <param name="transactionType">Type of the transaction.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="secret">The secret.</param>
        /// <returns>System.String.</returns>
        public static string GetSignature(int amount,
                                          string order,
                                          int merchantCode,
                                          int currency,
                                          int sum,
                                          RedsysTransactionType transactionType,
                                          string callback,
                                          string secret)
        {
           
       
            string input = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}",
                                          amount,
                                          order,
                                          merchantCode,
                                          currency,
                                          sum,
                                          (char)transactionType,
                                          callback,
                                          secret);
            Debug.WriteLine("Sha1 input: "+input);
            return Hash(input);
        }

        /// <summary>
        /// Gets a SHA1 signature for extended authorization requests.
        /// </summary>
        /// <param name="amount">The amount.</param>
        /// <param name="order">The order.</param>
        /// <param name="merchantCode">The merchant code.</param>
        /// <param name="currency">The currency.</param>
        /// <param name="transactionType">Type of the transaction.</param>
        /// <param name="callback">The callback.</param>
        /// <param name="secret">The secret.</param>
        /// <returns>System.String.</returns>
        public static string GetSignature(int amount,
                                          string order,
                                          int merchantCode,
                                          int currency,
                                          RedsysTransactionType transactionType,
                                          string callback,
                                          string secret)
        {
            string input = string.Format("{0}{1}{2}{3}{4}{5}{6}",
                                          amount,
                                          order,
                                          merchantCode,
                                          currency,
                                          (char)transactionType,
                                          callback,
                                          secret);
            Debug.WriteLine("Sha1 input: " + input);
            return Hash(input);
        }

        /// <summary>
        /// Gets a SHA1 signature for standard authorization requests.
        /// </summary>
        /// <param name="amount">The amount.</param>
        /// <param name="order">The order.</param>
        /// <param name="merchantCode">The merchant code.</param>
        /// <param name="currency">The currency.</param>
        /// <param name="secret">The secret.</param>
        /// <returns>System.String.</returns>
        public static string GetSignature(int amount, string order, int merchantCode, int currency, string secret)
        {
            string input = string.Format("{0}{1}{2}{3}{4}", amount, order, merchantCode, currency, secret);
            Debug.WriteLine("Sha1 input: " + input);
            return Hash(input);
        }

        /// <summary>
        /// Gets a SHA1 signature for standard recurring transaction requests.
        /// </summary>
        /// <param name="amount">The amount.</param>
        /// <param name="order">The order.</param>
        /// <param name="merchantCode">The merchant code.</param>
        /// <param name="currency">The currency.</param>
        /// <param name="sum">The sum.</param>
        /// <param name="secret">The secret.</param>
        /// <returns>System.String.</returns>
        public static string GetSignature(int amount, string order, int merchantCode, int currency, int sum, string secret)
        {
            string input = string.Format("{0}{1}{2}{3}{4}{5}",
                                         amount,
                                         order,
                                         merchantCode,
                                         currency,
                                         sum,
                                         secret);
            Debug.WriteLine("Sha1 input: " + input);
            return Hash(input);
        }

        /// <summary>
        /// Determines whether notification is valid.
        /// </summary>
        /// <param name="amount">The amount.</param>
        /// <param name="order">The order.</param>
        /// <param name="merchantCode">The merchant code.</param>
        /// <param name="currency">The currency.</param>
        /// <param name="response">The response.</param>
        /// <param name="secret">The secret.</param>
        /// <param name="signature">The signature.</param>
        /// <returns><c>true</c> if [notification is valid]; otherwise, <c>false</c>.</returns>
        public static bool IsNotificationValid(decimal amount,
                                               string order,
                                               string merchantCode,
                                               int currency,
                                               int response,
                                               string secret,
                                               string signature)
        {
            int intAmount = (int)Math.Round(amount * 100, 2);
            string input = intAmount + order + merchantCode + currency + response + secret;
            string hash = Hash(input);
            return string.Equals(hash, signature, StringComparison.CurrentCultureIgnoreCase);
        }
    }
}